这个头文件提供 浮点数环境 的相关功能,例如浮点异常处理、舍入方向控制等。
需要链接数学库,例如在 gcc 中需要添加 -lm
链接选项。
浮点环境功能依赖于硬件和编译器的具体实现,可能需要手动开启:
- 通过
#pragma STDC FENV_ACCESS ON
预处理指令可以开启浮点环境功能。
- 通过
#pragma STDC FENV_ACCESS OFF
预处理指令可以关闭浮点环境功能。
- 部分硬件或编译器可能不支持。
#include <stdio.h>
#include <fenv.h>
#include <math.h>
#include <errno.h>
void show_exceptions(void) {
printf("当前浮点异常状态: ");
if (fetestexcept(FE_ALL_EXCEPT) == 0) {
printf("无异常\n");
return;
}
if (fetestexcept(FE_DIVBYZERO)) printf("除零异常 ");
if (fetestexcept(FE_INVALID)) printf("无效操作异常 ");
if (fetestexcept(FE_OVERFLOW)) printf("上溢异常 ");
if (fetestexcept(FE_UNDERFLOW)) printf("下溢异常 ");
if (fetestexcept(FE_INEXACT)) printf("不精确结果异常 ");
printf("\n");
}
void show_rounding_mode(void) {
printf("当前舍入模式: ");
switch (fegetround()) {
case FE_TONEAREST: printf("四舍五入\n"); break;
case FE_DOWNWARD: printf("向负无穷方向舍入\n"); break;
case FE_UPWARD: printf("向正无穷方向舍入\n"); break;
case FE_TOWARDZERO: printf("向零舍入\n"); break;
default: printf("未知模式\n");
}
}
int main(void) {
printf("=== 初始浮点环境 ===\n");
show_exceptions();
show_rounding_mode();
printf("\n");
printf("=== 触发浮点异常 ===\n");
feclearexcept(FE_ALL_EXCEPT);
double x = 1.0, y = 0.0;
double z = x / y;
printf("1.0 / 0.0 = %f\n", z);
show_exceptions();
double a = sqrt(-1.0);
printf("sqrt(-1.0) = %f\n", a);
show_exceptions();
printf("\n");
printf("=== 舍入模式控制 ===\n");
fesetround(FE_DOWNWARD);
show_rounding_mode();
double num = 1.75;
printf("1.75 舍入后: %f\n", rint(num));
fesetround(FE_UPWARD);
show_rounding_mode();
printf("1.75 舍入后: %f\n", rint(num));
fesetround(FE_TONEAREST);
printf("\n");
printf("=== 环境保存与恢复 ===\n");
fenv_t env;
fegetenv(&env);
fesetround(FE_TOWARDZERO);
feclearexcept(FE_ALL_EXCEPT);
printf("修改后的环境:\n");
show_rounding_mode();
show_exceptions();
fesetenv(&env);
printf("\n恢复后的环境:\n");
show_rounding_mode();
show_exceptions();
return 0;
}
运行结果:
user@host:~ $ gcc main.c -lm
user@host:~ $ ./a.out
=== 初始浮点环境 ===
当前浮点异常状态: 无异常
当前舍入模式: 四舍五入
=== 触发浮点异常 ===
1.0 / 0.0 = inf
当前浮点异常状态: 除零异常
sqrt(-1.0) = -nan
当前浮点异常状态: 除零异常 无效操作异常
=== 舍入模式控制 ===
当前舍入模式: 向负无穷方向舍入
1.75 舍入后: 1.000000
当前舍入模式: 向正无穷方向舍入
1.75 舍入后: 2.000000
=== 环境保存与恢复 ===
修改后的环境:
当前舍入模式: 向零舍入
当前浮点异常状态: 无异常
恢复后的环境:
当前舍入模式: 四舍五入
当前浮点异常状态: 除零异常 无效操作异常 不精确结果异常
类型 | 标准 | 说明 |
---|
fenv_t | C99 | 表示整个浮点环境的类型 |
fexcept_t | C99 | 表示整个浮点异常标志的类型 |
函数 | 标准 | 说明 |
---|
feclearexcep | C99 | 清除指定的浮点异常 |
fetestexcept | C99 | 检查指定的浮点异常 |
feraiseexcept | C99 | 产生指定的浮点异常 |
fegetexceptflag | C99 | 整体获取浮点异常标志 |
fesetexceptflag | C99 | 整体设置浮点异常标志 |
fegetround | C99 | 获取舍入方向 |
fesetround | C99 | 设置舍入方向 |
fegetenv | C99 | 获取浮点环境 |
fesetenv | C99 | 设置浮点环境 |
feholdexcept | C99 | 保存浮点环境并清空浮点异常 |
feupdateenv | C99 | 恢复浮点环境并触发浮点异常 |
宏 | 标准 | 说明 |
---|
FE_DFL_ENV | C99 | 指向默认浮点环境的指针 |
浮点数异常宏 | 标准 | 说明 |
---|
FE_ALL_EXCEPT | C99 | 所有支持的浮点异常的按位或 |
FE_DIVBYZERO | C99 | 浮点运算中发生了极点错误 |
FE_INEXACT | C99 | 结果不精确:需要进行舍入才能存储 |
FE_INVALID | C99 | 浮点运算中发生了域错误 |
FE_OVERFLOW | C99 | 浮点运算的结果太大而溢出 |
FE_UNDERFLOW | C99 | 浮点运算的结果太小而损失精度 |
浮点数舍入方向宏 | 标准 | 说明 |
---|
FE_DOWNWARD | C99 | 向负无穷方向舍入 |
FE_TONEAREST | C99 | 四舍五入到最接近的可表示值 |
FE_TOWARDZERO | C99 | 向零舍入 |
FE_UPWARD | C99 | 向正无穷方向舍入 |